
module xpip_rtl_lsu(
  input logic clk, rst_n,
  xpip_intf.lsu inf
);
  `XPIP_DEF_PARAM
  
  lsu_req_inf_s ri[2][NUM_LSV_RBUF/2], rin[2][NUM_LSV_RBUF/2];
  lsu_sreq_inf_s sri[2][NUM_LSV_SBUF], srin[2][NUM_LSV_SBUF];
  lsu_inf_s s, sn;
  lsu_io_inf_s io, ion;
  
  logic aWr[2];
  logic[WID_LSV_RBUF:0] aRadr[2], aWadr[2];
  lsu_adr_inf_s[NUM_SP-1:0] aDatai[2], aDatao[2];
  
  logic ssWr;
  logic[WID_LSV_STB0-1:0] ssRadr, ssWadr;
  lsu_sel_inf_s[NUM_VEC-1:0][WORD_BYTES-1:0] ssDatai, ssDatao;
  
  logic eaWr;
  logic[WID_LSV_STB0:0] eaRadr, eaWadr;
  lsu_exa_buf_s eaDatai, eaDatao;

  logic saWr;
  logic[MCV-1:0] saBe;
  logic[WID_LSV_RBUF-1:0] saRadr, saWadr;
  lwadr_t[NUM_SP-1:0] saDatai;
  lwadr_t[NUM_VEC-1:0] saDatao;

  logic[WID_LSV_SBUF:0] scRadr, scWadr;
  lsu_asbc_inf_s[NUM_VEC-1:0] scDatai, scDatao;
      
  logic dWr;
  logic[WID_LSV_RBUF:0] dRadr, dWadr;
  word[NUM_VEC-1:0] dDatai, dDatao;

  logic rWr;
  logic[WID_LSV_RBUF:0] rRadr, rWadr;
  logic[NUM_VEC-1:0] rBe;
  word[MCV-1:0][NUM_SP-1:0] rDatai, rDatao;
  
  always_ff@(posedge clk or negedge rst_n)
    if(!rst_n) begin
      ri <= '{default : lsu_req_inf_def};
      sri <= '{default : lsu_sreq_inf_def};
      s <= lsu_inf_def;
      io <= lsu_io_inf_def;
    end else begin
      ri <= rin;
      sri <= srin;
      s <= sn;
      io <= ion;
    end
    
  always_comb
  begin : comb_logic
    begin : init
    rin = ri;
    srin = sri;
    sn = s;
    
    aWr = '{default : '0};
    rWr = '0;
    ssWr = '0;
    saWr = '0;
    eaWr = '0;
    
    aDatai = '{default : '0};
    ssDatai = '0;
    rDatai = '0;
    eaDatai = '0;
    saDatai = '0;
    
    rBe =  '0;
    saBe = '0;
    
    aWadr = '{default : '0};
    ssWadr = s.stb0rdy;
    rWadr = '0;
    eaWadr = '0;
    
    eaRadr = s.eaRadr;
    rRadr = '0;
    ssRadr = s.stb0ds;
    dRadr = '0;
    
    sn.cyc++;
    if(io.isu[1].last)
      sn.cyc = '0;
    sn.asp[1] = s.asp[0];
    sn.asp[2] = s.asp[1];
    end : init
    
    begin : isu_req
    ///new isu req
    if(io.isu[2].req) begin
      logic anyv;
      anyv = '0;
      aWr[s.ls] = '1;
      saWr = '1;
      aWadr[s.ls] = {s.es, s.cyc};
      if(rin[s.ls][s.es].st == rs_no)
        rin[s.ls][s.es].st = rs_as_rdy;
      
      if(!io.isu[2].ls) begin
        for(int i = 0; i < NUM_SP; i++)
          sn.rfsdb[s.cyc][i] = io.rfu.d[i];
      end
      
      for(int i = 0; i < NUM_SP; i++) begin
        word adr;
        logic c, m;

        adr = io.rfu.b[i] + {`TBE(io.rfu.imm), io.rfu.imm};
        aDatai[s.ls][i].adr = adr;
        saDatai[i] = adr;
        saBe[s.cyc] = '1;
        rin[s.ls][s.es].v[s.cyc][i] = io.rfu.v[i];
        rin[s.ls][s.es].rr[s.cyc][i] = io.rfu.v[i] ? rr_np : rr_inv;
        anyv |= io.rfu.v[i];
      end
      
      if(s.cyc == '0)
        sn.bcnt[s.ls]++;
      
      rin[s.ls][s.es].vas[s.cyc] = anyv;
      rin[s.ls][s.es].wrf = io.isu[2].wrf;
      rin[s.ls][s.es].lid = io.isu[2].lid;
      rin[s.ls][s.es].ltid = io.isu[2].ltid;
      rin[s.ls][s.es].ls = io.isu[2].ls;
      rin[s.ls][s.es].fun = io.isu[2].fun;
      rin[s.ls][s.es].ch = io.isu[2].ch;
      rin[s.ls][s.es].prot = io.isu[2].prot;
      rin[s.ls][s.es].lg = io.isu[2].lg;
      rin[s.ls][s.es].gid = io.isu[2].gid;
      rin[s.ls][s.es].oid = io.isu[2].oid;
      rin[s.ls][s.es].asyn = io.isu[2].asyn;
    end
    end : isu_req
    
    begin : adr_select
    ///stage 1 adr select
    for(int i = 0; i < 2; i++) begin
      lsu_req_inf_s tr;
      vadr2_t vadr;

      tr = ri[i][s.asp[1][i].rid];
      sn.asp[2][i].sm = '0;
                    
      if(s.asp[1][i].start && s.asp[1][i].v)
        for(int j = 0; j < NUM_SP; j++)
          if(tr.v[s.asp[1][i].cyc][j]) begin
            sn.as2adr[i] = io.aDatao[i][j].adr;
            break;
          end

      vadr = sn.as2adr[i];
      for(int j = 0; j < NUM_SMTLB_TGRP; j++)
        if((vadr.vpn.msk & ~page_mask_table[inf.cfg.smTyp[tr.gid][j]]) == inf.cfg.smVpn[tr.gid][j].msk
        && vadr.vpn.v2 == inf.cfg.smVpn[tr.gid][j].v2) begin
          sn.asp[2][i].sm = '1;
          sn.asp[2][i].tlbId = j;
        end
      /*
      if(vadr < VADR_MAPPED) begin
        sn.asp[2][i].cache = '1;
        sn.asp[2][i].map = '1;
      end else if(vadr < VADR_NMAPNC) begin
      end else if(vadr < VADR_EJTAGS) begin
      end else begin
        sn.asp[2][i].cache = '1;
        sn.asp[2][i].map = '0;          
      end
      */
      if(s.asp[1][i].v)
        for(int j = 0; j < NUM_SP; j++) begin
          if(sn.asp[2][i].sm && !sn.asp[2][i].llsc) begin
            vadr2_t a0, a1;
            pageMsk_t msk;
            msk = ~page_mask_table[inf.cfg.smTyp[tr.gid][sn.asp[2][i].tlbId]];
            a0 = io.aDatao[i][j].adr;
            a1 = sn.as2adr[i];
            sn.as2[i][j].v = tr.v[s.asp[1][i].cyc][j] && (a0.vpn.v2 == a1.vpn.v2)
                             && ((a0.vpn.msk & msk) == (a1.vpn.msk & msk)); 
          end else begin
            vadr_t a0, a1;
            a0 = io.aDatao[i][j].adr;
            a1 = sn.as2adr[i];
            sn.as2[i][j].v = a1.idx == a0.idx && a1.ua == a0.ua
                             && a1.par == a0.par && tr.v[s.asp[1][i].cyc][j];
          end
        end
      else
        for(int j = 0; j < NUM_SP; j++)
          sn.as2[i][j].v = '0;
      
      ///search current sub-vec for shared mem merge
      for(int j = 0; j < NUM_SP; j++) begin
        logic merge;
        spid_t mid;
        vadr_t a0, a1;
        
        a0 = io.aDatao[i][j].adr;
        merge = '0;
        mid = '0;
        
        for(int k = 0; k < NUM_SP; k++) begin
          a1 = io.aDatao[i][k].adr;
          if(k <= j) continue;
          if(sn.asp[2][i].sm && sn.as2[i][k].v && a0.cl == a1.cl 
          && a0.idx == a1.idx && a0.par == a1.par && a0.ua == a1.ua) begin
            merge = '1;
            mid = k;
          end
        end
        sn.as2[i][j].m = merge;
        sn.as2[i][j].mid = mid;
///        if(sn.as2[i][j].v)
        sn.as2[i][j].adr = io.aDatao[i][j].adr;
      end
                
      ///stage 2, select NUM_ASB_CYC req
      if(s.asp[2][i].start) begin
        for(int j = 0; j < NUM_SP; j++)
          sn.as3[i][j].v = '0;
              
        for(int j = 0; j < NUM_ASB_CYC; j++)
          for(int k = 0; k < NUM_SMEM_BK; k++) begin
            sn.exav[i][j][k] = '0;
            sn.exa[i][j][k].bv = '0;
          end
      end
       
      for(int j = 0; j < NUM_SMEM_BK; j++) begin
        asbc2_t cnt;
        cnt = s.ascnt[i][j];
        for(int k = 0; k < NUM_SP; k++) begin
          if(cnt == NUM_ASB_CYC)
            break;
          if(s.as2[i][k].v && !s.as2[i][k].m && s.as2[i][k].adr.bk == j) begin
            sn.as3[i][k].v = '1;
            sn.as3[i][k].c = cnt;
            sn.exa[i][cnt][j].adr = (s.as2[i][k].adr >> (WID_SMEM_BK + WID_WORD));
            sn.exav[i][cnt][j] = '1;
            cnt++;
          end
        end
        sn.ascnt[i][j] = cnt;
      end
      
      ///stage 2, fill asb
      if(s.asp[2][i].v) begin
        lsu_req_inf_s tr;
        logic bt[2];
        os_t os;
        
        tr = ri[i][s.asp[2][i].rid];
        bt = '{default : '0};

        if(tr.ls) begin
          case(tr.fun)
            memld_byte,
            memld_ubyte:  bt[0] = '1;
            memld_half,
            memld_uhalf:  bt[1] = '1;
          endcase
        end else begin
          case(tr.fun)
            memst_byte:  bt[0] = '1;
            memst_half:  bt[1] = '1;
          endcase
        end
        
        if(!s.asp[2][i].llsc)
          for(int j = 0; j < NUM_SP; j++) begin
            if(s.as2[i][j].mb) begin
              sn.as3[i][j].v = '1;
              sn.as3[i][j].c = s.as2[i][j].c;
            end else if(s.as2[i][j].m) begin
              sn.as3[i][j].v = sn.as3[i][s.as2[i][j].mid].v;
              sn.as3[i][j].c = sn.as3[i][s.as2[i][j].mid].c;
            end
          end
        
        for(int j = 0; j < NUM_SMEM_BK; j++)
          for(int k = 0; k < NUM_ASB_CYC; k++) begin
            if(tr.ls) begin
              bk_t bk;
              asbc_t c;
              spid_t sp;
              cyc_t cyc;
              c = k;
              bk = j;
              {cyc, sp} = {c, bk};
              os = s.as2[i][sp].adr.os;
              if(s.asp[2][i].cyc == cyc && sn.as3[i][sp].v) begin
                {cyc, sp} = {sn.as3[i][sp].c, s.as2[i][sp].adr.bk};
                if(bt[0]) begin
                  sn.asb[i][k][j][0].c = cyc;
                  sn.asb[i][k][j][0].s = sp;
                  sn.asb[i][k][j][0].o = os;
                end else if(bt[1]) begin
                  os &= 'b10;
                  sn.asb[i][k][j][0].c = cyc;
                  sn.asb[i][k][j][0].s = sp;
                  sn.asb[i][k][j][0].o = os;
                  os |= 'b01;
                  sn.asb[i][k][j][1].c = cyc;
                  sn.asb[i][k][j][1].s = sp;
                  sn.asb[i][k][j][1].o = os;
                end else begin
                  for(int o = 0; o < WORD_BYTES; o++) begin
                    sn.asb[i][k][j][o].c = cyc;
                    sn.asb[i][k][j][o].s = sp;
                    sn.asb[i][k][j][o].o = o;
                  end
                end              
              end
            end

            for(int l = 0; l < NUM_SP; l++)
              if(sn.as3[i][l].v && sn.as3[i][l].c == k && s.as2[i][l].adr.bk == j) begin
                os = s.as2[i][l].adr.os;
                if(bt[0])
                    sn.exa[i][k][j].bv[os] = '1;
                else if(bt[1]) begin
                  os &= 'b10;
                  sn.exa[i][k][j].bv[os] = '1;
                  os |= 'b01;
                  sn.exa[i][k][j].bv[os] = '1;
                end else begin
                  for(int o = 0; o < WORD_BYTES; o++)
                    sn.exa[i][k][j].bv[os] = '1;
                end
              end
          end
          
        for(int j = 0; j < NUM_SP; j++) begin
          sn.asbc[i][s.asp[2][i].cyc][j].c = sn.as3[i][j].c;
          sn.asbc[i][s.asp[2][i].cyc][j].v = sn.as3[i][j].v;
        end
      end
      
      ///stage 1, check buffer for merge
      for(int j = 0; j < NUM_SP; j++) begin
        bk_t bk;
        bk = sn.as2[i][j].adr.bk;
        sn.as2[i][j].mb = '0;
        if(!sn.as2[i][j].v)
          continue;
        for(int k = 0; k < NUM_ASB_CYC; k++) begin
          if(sn.exa[i][k][bk].adr == (sn.as2[i][j].adr >> (WID_SMEM_BK + WID_WORD))
          && sn.exav[i][k][bk]) begin
            sn.as2[i][j].mb = '1;
            sn.as2[i][j].c = k;
          end
        end
      end
      
      ///update ri
      if(s.asp[2][i].v)begin
        logic v, v2;
        lsu_ads_pip_inf_s asp;
        asp = s.asp[2][i];
        {v, v2} = '0;
        for(int j = 0; j < NUM_SP; j++) begin
          rin[i][asp.rid].v[asp.cyc][j] &= !sn.as3[i][j].v;
          v |= rin[i][asp.rid].v[asp.cyc][j];
          v2 |= sn.as3[i][j].v;
        end
        rin[i][asp.rid].vas[asp.cyc] = v;
        if(asp.start)
          sn.vsas[i] = '0;
        if(!asp.ls)
          sn.vsas[i][asp.cyc] = v2;
        if(asp.wb) begin
          rin[i][asp.rid].st = (rin[i][asp.rid].vas == '0 || asp.llsc) ? rs_w_sreq : rs_as_rdy;
          if(asp.ls)
            for(int j = 0; j < MCV; j++) begin
              v = '0;
              for(int k = 0; k < NUM_SP; k++) begin
                asbc_t c;
                bk_t bk;
                cyc_t cyc;
                spid_t sp;
                cyc = j;
                sp = k;
                {c, bk} = {cyc, sp};
                v |= sn.exav[i][c][bk];
              end
              srin[1][asp.sid].vds[j] = v;
            end
          else begin
            srin[0][asp.sid].vds = sn.vsas[i];
            for(int c = 0; c < NUM_ASB_CYC; c++) begin
              v = '0;
              for(int bk = 0; bk < NUM_SMEM_BK; bk++) begin
                v |= sn.exav[i][c][bk];
              end
              srin[0][asp.sid].dv[c] = v;
            end
          end
        end
      end
    end
    
    ///select a ri for address processing
    begin
    logic noLd[3], noSt[3], lid;
    noSt[0] = sn.sstcnt == '1 || sn.stb0f;
    noLd[0] = sn.sldcnt == '1 || sn.ltb0f;
    noSt[1] = noSt[0];
    noLd[1] = noLd[0];
    noSt[2] = noSt[0] || (sn.sstcnt == ('1 - 1'b1) || (s.stb0wp + 1'b1) == s.stb0rp);
    noLd[2] = noLd[0] || (sn.sldcnt == ('1 - 1'b1) || (s.ltb0wp + 1'b1) == s.ltb0rp);
                        
    for(int i = 0; i < 2; i++) begin
      sn.asp[0][i].start = '0;
      sn.asp[0][i].v = '0;
      sn.asp[0][i].wb = '0;
      lid = i;
      
      if(s.asp[0][i].wb)
        sn.asp[0][i].kp = '0;
        
      if(!sn.asp[0][i].kp) begin
        for(int j = 0; j < (NUM_LSV_RBUF / 2); j++)
          if(rin[i][j].st == rs_as_rdy) begin
            if((noSt[i] && !rin[i][j].ls) || (noLd[i] && rin[i][j].ls))
              continue;
            sn.asp[0][i].rid = j;
            sn.asp[0][i].start = '1;
            sn.asp[0][i].kp = '1;
            sn.asp[0][i].llsc = rin[i][j].ls ? rin[i][j].fun == memld_link : rin[i][j].fun == memst_cond;
            sn.asp[0][i].ls = rin[i][j].ls;
            rin[i][j].st = rs_as;
            rin[i][j].srcnt++;
            sn.vas[i] = (s.ls == i && s.es == j) ? '1 : rin[i][j].vas;  
            if(rin[i][j].ls) begin
              sn.ltb0wp++;
              sn.sldcnt++;
              noLd[1] = noLd[2];
            end else begin
              sn.stb0wp++;
              sn.sstcnt++;
              noSt[1] = noSt[2];
            end
            break;
          end
      end
      
      ///process next adr sub-vec
      for(int j = 0; j < MCV; j++)
        if(sn.vas[i][j]) begin
          sn.asp[0][i].cyc = j;
          sn.vas[i][j] = '0;
          sn.asp[0][i].v = '1;
          break;
        end
      aRadr[i] = {sn.asp[0][i].rid, sn.asp[0][i].cyc};
    end
    
    if(sn.asp[0][lid].start) begin
      for(int i = 0; i < NUM_LSV_SBUF; i++)
        if(!srin[sn.asp[0][lid].ls][i].v) begin
          sn.asp[0][lid].sid = i;
          break;
        end
      srin[sn.asp[0][lid].ls][sn.asp[0][lid].sid].v = '1;
      srin[sn.asp[0][lid].ls][sn.asp[0][lid].sid].rlid = lid;
      srin[sn.asp[0][lid].ls][sn.asp[0][lid].sid].rid = sn.asp[0][lid].rid;
    end
            
    lid = s.asp[0][0].wb;
    if(!(sn.vas[lid] == '0 && sn.asp[0][lid].kp))
      lid = !lid;
    sn.asp[0][lid].wb = sn.vas[lid] == '0 && sn.asp[0][lid].kp;
    
    lid = s.asp[2][1].wb;
    if(s.asp[2][lid].wb) begin
      ssDatai = sn.asb[lid];
      scDatai = sn.asbc[lid];
      eaDatai.exa = sn.exa[lid];
      eaDatai.adr = s.as2adr[lid];
      eaDatai.sm = s.asp[2][lid].sm;
      eaWr = '1;
      if(ri[lid][s.asp[2][lid].rid].ls) begin
        eaWadr = s.ltb0rdy + NUM_LSV_STB0;
        scWadr = {1'b1, s.asp[2][lid].sid};
        sn.ltb0[s.ltb0rdy] = s.asp[2][lid].sid;
        sn.ltb0rdy++;
      end else begin
        eaWadr = s.stb0rdy;
        scWadr = {1'b0, s.asp[2][lid].sid};
        sn.stb0[s.stb0rdy] = s.asp[2][lid].sid;
        sn.stb0rdy++;
        ssWr = '1;
      end
    end
    end
    
    ///select a new entry
    if(s.cyc == '1 || sn.bcnt[s.ls] == '1) begin
      lsbid_t minl;
      minl = '1;
      sn.ls = '0;
      
      for(int i = 0; i < 2; i++)
        if(sn.bcnt[i] < minl) begin
          sn.ls = i;
          minl = sn.bcnt[i];
        end
      for(int i = 0; i < (NUM_LSV_RBUF / 2); i++)
        if(rin[sn.ls][i].st == rs_no) begin
          sn.es = i;
          break;
        end
    end
    
    sn.lsu2isu.vblock = (sn.bcnt[0] + sn.bcnt[1] + io.isu[0].req + io.isu[1].req) >= {{(WID_LSV_RBUF-2){1'b1}}, 2'b01};
    end : adr_select
    
    begin : dcu_req_rsp
    ///store data & adr rsp process
    
    ///select a data to req
    if(io.lsu2dcu.req.sd && io.dcu.rsp.sd) begin
      sn.stb1rp++;
      sn.stb01dif++;
    end
    
    sn.stallDCUsdReq = io.lsu2dcu.req.sd && !io.dcu.rsp.sd;
    sn.dcuSdReq = sn.stb1rp != sn.stb1rdy || sn.stb1rf;
    sn.startDCUsdReq = sn.dcuSdReq && !sn.stallDCUsdReq;
    sn.sdExId = sn.stb1[s.stb1rp];
    if(sn.startDCUsdReq)      
      rRadr = NUM_LSV_RBUF + s.stb1rp;
    
    ///select a adr to req
    if(io.lsu2dcu.req.a && io.dcu.rsp.a) begin
      if(io.lsu2dcu.ar.ls) begin
        sn.ltb0rp++;
      end else begin
        sn.stb01dif--;
        sn.stb0rp++;
      end
    end
    
    sn.stallDCUaReq = io.lsu2dcu.req.a && !io.dcu.rsp.a;
    sn.dcuAReq = sn.stb01dif != '0 || (sn.ltb0rp != sn.ltb0rdy || sn.ltb0rf);
    
    if(sn.stb01dif != '0) begin
      sn.aExId = sn.stb0[s.stb0rp];
      sn.aExLs = 1'b0;
      sn.eaRadr = {1'b0, s.stb0rp};
    end else if(sn.dcuAReq) begin
      sn.aExId = sn.ltb0[s.ltb0rp];
      sn.aExLs = 1'b1;
      sn.eaRadr = s.ltb0rp + NUM_LSV_STB0;
    end
    eaRadr = sn.eaRadr;
    
    ///if rf not writing the data ram, ex ld data write
    if(io.dcu.req.ld && io.lsu2dcu.rsp.ld) begin
      sn.ltb1[s.ltb1wp].id = io.dcu.ld.id;
      sn.ltb1[s.ltb1wp].exp = io.dcu.ld.exp;
      sn.ltb1wp++;
    end
    
    if(io.dcu.req.s && io.lsu2dcu.rsp.s) begin
      sn.stb2[s.stb2wp] = io.dcu.s;
      sn.stb2wp++;
    end
    end : dcu_req_rsp

    begin : data_select
      logic lid, stExpV, stExpWb;
      sn.dsp[1] = s.dsp[0];
      stExpV = '1;
      stExpWb = '1;
      
      ///data switch
      for(int i = 0; i < 2; i++) begin
        logic[WORD_BYTES-1:0] bv;
        logic rlid;
        lsbid_t rid;
        rid = s.dsp[1][i].rid;
        rlid = s.dsp[1][i].rlid;
                  
        if(s.dsp[0][i].start)
          sn.vsds[i] = sri[s.dsp[0][i].ls][s.dsp[0][i].sid].vds;
        for(int k = 0; k < MCV; k++)
          if(sn.vsds[i][k]) begin
            sn.dsp[1][i].cyc = k;
            sn.vsds[i][k] = '0;
            break;
          end
        
        bv = '1;  
        if(s.dsp[1][i].ls) begin
          case(s.dsp[1][lid].fun)
            memld_byte,
            memld_ubyte:  bv = 'b01;
            memld_half,
            memld_uhalf:  bv = 'b011;
          endcase
        end
                      
        ///data switch
        for(int j = 0; j < NUM_VEC; j++) begin
          lsu_sel_inf_s sel2;
          cyc_t cyc;
          spid_t sp;
          {cyc, sp} = j;
          sel2 = {io.scDatao[i][j].c, io.saDatao[i][j]};
          if(sel2.c == s.dsp[1][i].cyc) begin
            lsu_rrsp_e rr;
            rr = rr_inv;
            case(s.dsExp[i][s.dsp[1][i].cyc][sel2.s])
              exr_ok    : rr = s.dsp[1][lid].fun == memld_link ?  rr_np : rr_ok;
              exr_exok  : rr = rr_ok;
              exr_err   : rr = rr_err;
              exr_tlb   : rr = rr_np;
            endcase            
            sn.resr[i][j] = rr;
          end
          for(int o = 0; o < WORD_BYTES; o++) begin
            lsu_sel_inf_s sel;
            if(s.dsp[1][i].ls) begin
              sel = sel2;
              case(s.dsp[1][lid].fun)
                memld_word,
                memld_link:   sel.o = o;
                memld_half,
                memld_uhalf:  sel.o[0] = o;
              endcase
            end else
              sel = io.ssDatao[i][j][o];
            if(sel.c == s.dsp[1][i].cyc)
              sn.resb[i][cyc][sp][o] = bv[o] ? io.srcb[i][s.dsp[1][i].cyc][sel.s][sel.o] : '0;
          end
        end
      end
      
      ///data select finishing
      sn.dsp[1][0].wb = '0;
      sn.dsp[1][1].wb = '0;
      
      lid = s.dsp[0][0].wb;
      if(!(s.dsp[0][lid].v && sn.vsds[lid] == '0))
        lid = !lid;
      if(s.dsp[0][lid].v && sn.vsds[lid] == '0) begin
        sn.dsp[1][lid].wb = '1;
        sn.dsp[0][lid].v = '0;
        stExpWb = !s.dsp[0][lid].ls;
      end
      
      lid = s.dsp[1][1].wb;
      if(s.dsp[1][lid].wb) begin
        lsbid_t rid;
        logic rlid;
        rid = s.dsp[1][lid].rid;
        rlid = s.dsp[1][lid].rlid;
        rWr = '1;
        if(s.dsp[1][lid].ls) begin
          for(int i = 0; i < NUM_VEC; i++)
            rBe[i] = io.scDatao[lid][i].v;
          rin[rlid][rid].srcnt--;
          sn.sldcnt--;
          srin[1][s.dsp[1][lid].sid].v = '0;
          if(rin[rlid][rid].srcnt == '0 && rin[rlid][rid].st == rs_w_sreq)
            rin[rlid][rid].st = rs_w_wb;
          rWadr = {rlid, rid};
        end else begin
          rBe = '1;
          rWadr = NUM_LSV_RBUF + s.stb1rdy;
          sn.stb1[sn.stb1rdy] = s.dsp[1][lid].sid;
          sn.stb1rdy++;
        end
      end
      rDatai = sn.resb[lid];
            
      ///select data to switch
      sn.dsp[0][0].start = '0;
      sn.dsp[0][1].start = '0;
      lid = s.dsp[0][0].start;
      sn.dsExpRd = sn.ltb1[sn.ltb1rp].exp;
      if(sn.dsp[0][lid].v)
        lid = !lid;
      if(!sn.dsp[0][lid].v) begin
        if(sn.ltb1wp != sn.ltb1rp || sn.ltb1f) begin
          sn.dsp[0][lid].start = '1;
          sn.dsp[0][lid].v = '1;
          sn.dsp[0][lid].sid = sn.ltb1[sn.ltb1rp].id;
          sn.dsp[0][lid].rid = srin[1][sn.dsp[0][lid].sid].rid;
          sn.dsp[0][lid].rlid = srin[1][sn.dsp[0][lid].sid].rlid;
          sn.dsp[0][lid].ls = '1;
          sn.dsp[0][lid].fun = ri[sn.dsp[0][lid].rlid][sn.dsp[0][lid].rid].fun;
          saRadr = {sn.dsp[0][lid].rlid, sn.dsp[0][lid].rid};
          scRadr = {1'b1, sn.dsp[0][lid].sid};
          dRadr = NUM_LSV_RBUF + s.ltb1rp;
          sn.ltb1rp++;
          stExpV = '0;
        end else if((sn.stb0rdy != sn.stb0ds || sn.stb0rf) && !s.stb1f)begin
          sn.dsp[0][lid].start = '1;
          sn.dsp[0][lid].v = '1;
          sn.dsp[0][lid].sid = sn.stb0[sn.stb0ds];
          sn.dsp[0][lid].rid = srin[0][sn.dsp[0][lid].sid].rid;
          sn.dsp[0][lid].rlid = srin[0][sn.dsp[0][lid].sid].rlid;
          sn.dsp[0][lid].ls = '0;
          sn.dsp[0][lid].fun = ri[sn.dsp[0][lid].rlid][sn.dsp[0][lid].rid].fun;
          sn.stb0ds++;
          sn.stb1wp++;
          dRadr = {1'b0, sn.dsp[0][lid].rlid, sn.dsp[0][lid].rid};
        end
      end
      
      for(int i = 0; i < 3; i++)
        if(s.dsp[0][i].start)
          sn.dsExp[i] = s.dsExpRd;
            
      for(int j = 0; j < NUM_VEC; j++) begin
        lsu_sel_inf_s sel2;
        lsu_rrsp_e rr;
        cyc_t cyc;
        spid_t sp;
        {cyc, sp} = j;
        sel2 = {io.scDatao[2][j].c, io.saDatao[2][j]};
        rr = rr_inv;
        case(s.dsExp[2][sel2.c][sel2.s])
          exr_ok    : rr = s.dsp[1][2].fun == memst_cond ?  rr_np : rr_ok;
          exr_exok  : rr = rr_ok;
          exr_err   : rr = rr_err;
        endcase            
        sn.resr[2][j] = rr;
      end
      
      sn.dsp[0][2].start = '0;
      sn.dsp[1][2].wb = stExpWb && s.dsp[0][2].v;
      if(sn.dsp[1][2].wb)
        sn.dsp[0][2].v = '0;
      if((sn.stb2wp != sn.stb2rp || sn.stb2f) && !sn.dsp[0][2].v && stExpV) begin
        sn.dsExpRd = sn.stb2[sn.stb2rp].exp;
        sn.dsp[0][2].start = '1;
        sn.dsp[0][2].v = '1;
        sn.dsp[0][2].sid = sn.stb2[sn.stb2rp].id;
        sn.dsp[0][2].rid = sri[0][sn.dsp[0][2].sid].rid;
        sn.dsp[0][2].rlid = sri[0][sn.dsp[0][2].sid].rlid;
        sn.dsp[0][2].ls = '0;
        sn.dsp[0][2].fun = ri[sn.dsp[0][2].rlid][sn.dsp[0][2].rid].fun;
        scRadr = {1'b0, sn.stb2[sn.stb2rp].id};
        saRadr = {sri[0][sn.stb2[sn.stb2rp].id].rlid, sri[0][sn.stb2[sn.stb2rp].id].rid};
        sn.stb2rp++;
      end
      
      for(int i = 0; i < 3; i++)
        if(s.dsp[1][i].wb) begin
          lsbid_t rid;
          logic rlid;
          rid = s.dsp[1][i].rid;
          rlid = s.dsp[1][i].rlid;
          for(int j = 0; j < NUM_VEC; j++) begin
            cyc_t cyc;
            spid_t sp;
            {cyc, sp} = j;
            if(io.scDatao[i][j].v)
              rin[rlid][rid].rr[cyc][sp] = sn.resr[i][j];
          end
          if(i == 2) begin
            rin[rlid][rid].srcnt--;
            sn.sstcnt--;
            srin[0][s.dsp[1][2].sid].v = '0;
            if(rin[rlid][rid].srcnt == '0 && rin[rlid][rid].st == rs_w_sreq)
              rin[rlid][rid].st = rs_w_wb;          
          end
          break;
        end
        
      sn.stb0f = sn.stb0rp == sn.stb0wp && (s.stb0rp == (s.stb0wp + 1'b1) || s.stb0f);
      sn.stb0rf = sn.stb0rp == sn.stb0rdy && (s.stb0rp == (s.stb0rdy + 1'b1) || s.stb0rf);
      sn.stb1f = sn.stb1rp == sn.stb1wp && (s.stb1rp == (s.stb1wp + 1'b1) || s.stb1f);
      sn.stb1rf = sn.stb1rp == sn.stb1rdy && (s.stb1rp == (s.stb1rdy + 1'b1) || s.stb1rf);
      sn.stb2f = sn.stb2rp == sn.stb2wp && (s.stb2rp == (s.stb2wp + 1'b1) || s.stb2f);
      sn.ltb0f = sn.ltb0rp == sn.ltb0wp && (s.ltb0rp == (s.ltb0wp + 1'b1) || s.ltb0f);
      sn.ltb1f = sn.ltb1rp == sn.ltb1wp && (s.ltb1rp == (s.ltb1wp + 1'b1) || s.ltb1f);
      sn.ltb0rf = sn.ltb0rp == sn.ltb0rdy && (s.ltb0rp == (s.ltb0rdy + 1'b1) || s.ltb0rf);
    end : data_select
    
    begin : rfwb_rfin
    ///if isu accept a load wb
    sn.stallFinalReq = s.lsu2isu.req && !io.isu[0].rsp;
    sn.startFinalReq = '0;
    if(!sn.stallFinalReq || !s.finalReq) begin
      logic noLd; ///dcu is reading res ram, no load req
      logic i;
      lsbid_t j;
      noLd = sn.startDCUsdReq;
      sn.finalReq = '0;
      for(int k = 0; k < NUM_LSV_RBUF; k++) begin
        i = k;
        j = k >> 1;
        if(rin[i][j].st == rs_w_wb) begin
          if(rin[i][j].ls && noLd)
            continue;
          rin[i][j].st = rs_no;
          sn.bcnt[i]--;
          sn.frLid = i;
          sn.frId = j;
          sn.startFinalReq = '1;
          sn.finalReq = '1;
          break;
        end
      end
      if(!noLd)
        rRadr = {sn.frLid, sn.frId};
    end
      
    if(!sn.stallFinalReq) begin
      sn.lsu2isu.req = s.finalReq;
      sn.lsu2isu.adr = ri[s.frLid][s.frId].wrf.adr;
      sn.lsu2isu.asyn = ri[s.frLid][s.frId].asyn;
      sn.lsu2isu.ls = ri[s.frLid][s.frId].ls;
      sn.lsu2isu.ltid = ri[s.frLid][s.frId].ltid;
      sn.lsu2isu.lid = ri[s.frLid][s.frId].lid;
      sn.lsu2isu.oid = ri[s.frLid][s.frId].oid;
      sn.lsu2isu.crfw = ri[s.frLid][s.frId].ls ? ri[s.frLid][s.frId].fun == memld_link :
                        ri[s.frLid][s.frId].fun == memst_cond;
    end
    inf.lsu2isu = sn.lsu2isu;
    end : rfwb_rfin
  end : comb_logic
  
  always_comb
  begin : iorsp_logic
    ion = io;
    ion.rfu = inf.rfu2lsu;
    ion.dcu = inf.dcu2lsu;
    ion.aDatao = aDatao;
    
    if(s.cyc == '1)
      ion.isu[2].req = '0;
    if(ion.isu[1].last)
      ion.isu[2] = io.isu[1];
    if(io.isu[0].last)
      ion.isu[1] = io.isu[0];
    ion.isu[1].last = ion.isu[0].last;
      
    if(inf.isu2lsu.req)
      ion.isu[0] = inf.isu2lsu;
    else begin
      ion.isu[0].req = '0;
      ion.isu[0].last = '0;
    end
    ion.isu[0].rsp = inf.isu2lsu.rsp;
    ion.isu[0].sRf = inf.isu2lsu.sRf;
    ion.isu[0].vRf = inf.isu2lsu.vRf;
    
///    if(!sn.stallDCUaReq)
    begin
      lsbid_t rid;
      logic rlid;
      rid = sri[s.aExLs][s.aExId].rid;
      rlid = sri[s.aExLs][s.aExId].rlid;
      ion.lsu2dcu.req.a = sn.dcuAReq;
      ion.lsu2dcu.ar.ls = sn.aExLs;

      ion.lsu2dcu.ar.rid = s.aExId;
      ion.lsu2dcu.ar.tid = {ri[rlid][rid].lid, ri[rlid][rid].ltid};
      ion.lsu2dcu.ar.gid = ri[rlid][rid].gid;
      ion.lsu2dcu.ar.lg = ri[rlid][rid].lg;
      ion.lsu2dcu.ar.ch = ri[rlid][rid].ch;
      ion.lsu2dcu.ar.prot = ri[rlid][rid].prot;
      ion.lsu2dcu.ar.llsc = ri[rlid][rid].fun inside {memst_cond, memld_link};
      ion.lsu2dcu.ar.chadr = eaDatao.adr;
      ion.lsu2dcu.ar.sm = eaDatao.sm;
      for(int i = 0; i < NUM_ASB_CYC; i++)
        for(int j = 0; j < NUM_SMEM_BK; j++) begin
          ion.lsu2dcu.ar.adr[i][j] = eaDatao.exa[i][j].adr;
          ion.lsu2dcu.ar.v[i][j] = eaDatao.exa[i][j].bv;
        end
    end
    
    if(s.startDCUsdReq)
      ion.dcuSD = rDatao;
    ion.lsu2dcu.req.sd = sn.dcuSdReq;
    ion.lsu2dcu.sd.id = s.sdExId;
    ion.lsu2dcu.sd.data = ion.dcuSD;
    ion.lsu2dcu.sd.dv = srin[0][s.sdExId].dv;
    inf.lsu2dcu = ion.lsu2dcu;
    
    dDatai = '0;
    dWadr = '0;
    dWr = '0;
    if(io.isu[2].req && s.cyc == '1 && !io.isu[2].ls) begin
      dDatai = sn.rfsdb;
      dWadr = {1'b0, s.ls, s.es};
      dWr = '1;
    end
    inf.lsu2dcu.rsp.ld = !dWr && !sn.ltb1f;
    inf.lsu2dcu.rsp.s = !sn.stb2f;
    if(io.dcu.req.ld && io.lsu2dcu.rsp.ld) begin
      dWr = '1;
      dWadr = s.ltb1wp + NUM_LSV_RBUF;
      dDatai = inf.dcu2lsu.ld.data;
    end
    ion.lsu2dcu.rsp = inf.lsu2dcu.rsp;
    
    if(s.startFinalReq)
      for(int i = 0; i < MCV; i++)
        for(int j = 0; j < NUM_SP; j++)
          ion.rfuLD[i][j] = rDatao[i][j];
    if(!sn.stallFinalReq) begin
      ion.lsu2rfu.data = ion.rfuLD;
      ion.lsu2rfu.adr = ri[s.frLid][s.frId].wrf.adr;
      ion.lsu2rfu.crfw = rin[s.frLid][s.frId].ls ? rin[s.frLid][s.frId].fun == memld_link
                         : rin[s.frLid][s.frId].fun == memst_cond;
      for(int m = 0; m < MCV; m++)
        for(int n = 0; n < NUM_SP; n++) begin
          ion.lsu2rfu.v[m][n] = ri[s.frLid][s.frId].rr[m][n] == rr_ok;
          ion.lsu2rfu.flag[m][n] = ri[s.frLid][s.frId].rr[m][n] == rr_np;
        end
    end
    inf.lsu2rfu = ion.lsu2rfu;
    
    for(int i = 0; i < 2; i++) begin
      if(s.dsp[0][i].start) begin
        ion.ssDatao[i] = ssDatao;
        ion.scDatao[i] = scDatao;
        ion.srcb[i] = dDatao;
        ion.saDatao[i] = saDatao;
      end
    end
    if(s.dsp[0][2].start)
      ion.scDatao[2] = scDatao;
  end : iorsp_logic

genvar i;  
for(i = 0; i < 2; i++) begin : lane
  xpip_ram #(
    .word_width ($bits(lsu_adr_inf_s) * NUM_SP),
    .addr_width (WID_LSV_RBUF + 1),
    .bc_width   ($bits(lsu_adr_inf_s)),
    .two_port   (1),
    .bp         (1)
  )aram(
    .clk,
    .wr     (aWr[i]),
    .be     ('1),
    .datai  (aDatai[i]),
    .datao  (aDatao[i]),
    .radr   (aRadr[i]),
    .wadr   (aWadr[i]),
    .datao_d()
  );
end : lane
    
  xpip_ram #(
    .word_width ($bits(word) * NUM_VEC),
    .addr_width (WID_LSV_RBUF + 1),
    .num_words  (NUM_LSV_RBUF + NUM_LSV_LTB1),
    .bc_width   ($bits(word)),
    .two_port   (1),
    .bp         (1)
  )dram(
    .clk,
    .wr     (dWr),
    .be     ('1),
    .datai  (dDatai),
    .datao  (dDatao),
    .radr   (dRadr),
    .wadr   (dWadr),
    .datao_d()
  );
  
  xpip_ram #(
    .word_width ($bits(lsu_sel_inf_s) * NUM_VEC * WORD_BYTES),
    .addr_width (WID_LSV_STB0),
    .num_words  (NUM_LSV_STB0),
    .two_port   (1),
    .bp         (1)
  )ssram(
    .clk,
    .wr     (ssWr),
    .be     ('1),
    .datai  (ssDatai),
    .datao  (ssDatao),
    .radr   (ssRadr),
    .wadr   (ssWadr),
    .datao_d()
  );

  xpip_ram #(
    .word_width ($bits(lsu_exa_buf_s)),
    .addr_width (WID_LSV_STB0 + 1),
    .num_words  (NUM_LSV_STB0 + NUM_LSV_LTB0),
    .two_port   (1),
    .bp         (1)
  )earam(
    .clk,
    .wr     (eaWr),
    .be     ('1),
    .datai  (eaDatai),
    .datao  (eaDatao),
    .radr   (eaRadr),
    .wadr   (eaWadr),
    .datao_d()
  );

  xpip_ram #(
    .word_width ($bits(word) * NUM_VEC),
    .addr_width (WID_LSV_RBUF + 1),
    .num_words  (NUM_LSV_RBUF + NUM_LSV_STB1),
    .bc_width   ($bits(word)),
    .two_port   (1),
    .bp         (1)
  )rram(
    .clk,
    .wr     (rWr),
    .be     (rBe),
    .datai  (rDatai),
    .datao  (rDatao),
    .radr   (rRadr),
    .wadr   (rWadr),
    .datao_d()
  );

  xpip_ram #(
    .word_width ($bits(lwadr_t) * NUM_VEC),
    .addr_width (WID_LSV_RBUF),
    .num_words  (NUM_LSV_RBUF),
    .bc_width   ($bits(lwadr_t) * NUM_SP),
    .two_port   (1)
  )saram(
    .clk,
    .wr     (saWr),
    .be     (saBe),
    .datai  ({MCV{saDatai}}),
    .datao  (saDatao),
    .radr   (saRadr),
    .wadr   (saWadr),
    .datao_d()
  );  

  xpip_ram #(
    .word_width ($bits(lsu_asbc_inf_s) * NUM_VEC),
    .addr_width (WID_LSV_SBUF + 1),
    .num_words  (NUM_LSV_RBUF * 2),
    .bc_width   ($bits(lsu_asbc_inf_s)),
    .two_port   (1),
    .bp         (1)
  )scram(
    .clk,
    .wr     (eaWr),
    .be     ('1),
    .datai  (scDatai),
    .datao  (scDatao),
    .radr   (scRadr),
    .wadr   (scWadr),
    .datao_d()
  ); 
endmodule